<?php
/**
 * Author:   tangxiaowen
 * Email:    846506584@qq.com
 * Date:     2019/3/12 0012
 * Describe: 订单管理类
 */
namespace app\index\controller;

use think\db;
use think\Request;
use think\model\Merge;
use app\common\controller\chuanglan\ChuanglanSmsApi as CLApi;
use app\common\controller\system\Docking;
use app\common\controller\order\Orderget;

class Order extends Base
{
    /**
     * 订单还款1 - 还款支付操作 畅捷银行卡支付
     * @param string $orderId 订单编号
     * @param string $payType 支付类型
     * @return object
     */
    public function changjie_huankuan()
    {
        $post = $this->request->param(true);
        $header =Request::instance()->header();
		$data['userId'] =$header['userid'];//用户ID
		$data['type'] =$post['type'];//还款类型 1还款 2续期
        if(!isset($post['AppID'])){
        	show_error_api('无效的订单ID');
        }
		
		$order =db('loans_applylist')->where('ID',$post['AppID'])->find(); 
		
		$Orderget=new Orderget();
		$get_days_fakuan=$Orderget ->get_days_fakuan(strtotime(date("Y-m-d"),time()),strtotime($order['YyFkTime']),$order);
		if($data['type']=='2'){
//			根据商品获取商品信息  其实就是获取几个开关
            $get_goods=$Orderget ->get_goods($order['ProductID']);
			if($get_days_fakuan['datas']==0){ //正常客户展期
//				根据产品的展期开关判断
				if($get_goods['Status']=='0'){
					show_error_api('该类型订单不许与展期');
					
				}
			}else{//逾期客户展期
			if($get_goods['Statusyuqi']=='0'){
					show_error_api('该类型订单不许与展期');
				}
			}
		}
       $user =Db::table('xb_mem_info')->where('ID',$header['userid'])->find();//用户数据
       $ret =Db::table('xb_renzen_bank')->where('UserID',$header['userid'])->find();
       if($ret){
           $data['BankNo'] =$ret['BankNo'];//银行卡号
       }else{
       	show_error_api('用户银行卡获取失败');
       }    
       if($order){
            $data['OrderSn'] =$order['OrderSn'];//applylist 订单号
		    $Payceshi=$Orderget->get_Payceshi();//获取支付环境
	        if($Payceshi=='1'){
	        	if($data['type']=='1'){ 
		            $data['Money']=$this->getOrderShould($order);//还款   应还金额
	        	}else if($data['type']=='2'){					 
		            $data['Money']=$order['zhanqifei'];//续期   应还金额
	        	}else{
	        		show_error_api('支付类型错误');
	        	}
	        }else{
		       $data['Money'] = '0.01';//放款金额
	        }
       }else{
       		show_error_api('用户订单获取失败');
       }
       $changpay= new \changpay\ChangPay;
       $data['PartnerId'] = $Orderget->get_changpay();//获取商户号
       $data['userId'] =$header['userid'];//用户标志
       $datas = $changpay->changjie_bank($data);
       if($datas['AcceptStatus']=='S'){
       	show_success_api($data=[],$message='提交成功,等待扣款', $status='1');
       }else{
         	show_error_api($datas['RetMsg']);
       }
    }

    /**
     * 订单还款1 - 还款支付操作
     * @param string $orderId 订单编号
     * @param string $payType 支付类型
     * @return object
     */
    public function orderPay()
    {
        //验证post数据
        $postData = Request()->only('orderId,payType');
        $result = $this->validate($postData,'Order.orderPay');
        if($result !== true){
            returnErrorResult($result);
        }

        //检测订单状态
        $orderInfo = $this->getOrderInfo($postData['orderId']);
        if(!$orderInfo || $orderInfo['LoanStatus'] != 2){
            returnErrorResult('订单不存在或不允许还款');
        }

        //获取订单应还款金额
        $orderMoney = $this->getOrderShould($orderInfo);

        //ping++支付
        (new Ping())->pay('用户还款',$orderInfo['OrderSn'],$orderMoney,($postData['payType'] == 1)?'alipay':'wx','用户还款');
    }

    /**
     * 订单还款2 - 还款支付成功后操作
     * @param string $pingOrderId ping支付记录单号
     * @param integer $amount 还款金额/元
     * @param int $created 还款时间
     * @param string $tradeNo 交易流水号
     * @param string $channel 支付方式
     */
    public function orderPayTwo($pingOrderId,$amount,$created,$tradeNo,$channel)
    {
        //获取ping支付记录与订单信息
        $pingOrderInfo = $this->getPingOrderInfo($pingOrderId);
        if(!$pingOrderInfo){
            \Think\Log::record('ping++支付回调 根据ping支付单号寻找贷款订单信息失败-还款 ping单号为 '.$pingOrderId);
            return false;
        }

        // 启动事务
        Db::startTrans();
        try {
            //修改贷款订单状态
            $loanOrder = [
                'LoanStatus' => 3,
                'SjFkTime'   => date('Y-d-d H:i:s',time()),
            ];
            $loanResult = Db::table('xb_loans_applylist')->where(['ID' => $pingOrderInfo['ID']])->update($loanOrder);
            if(!$loanResult){
                throw new \Exception('ping++支付回调 修改贷款订单状态失败 ping单号为 '.$pingOrderId);
            }

            //修改ping支付记录表
            $pingResult = Db::table('xb_pay_ping')->where(['ID' => $pingOrderInfo['PID']])->update(['Status' => 1]);
            if(!$pingResult){
                throw new \Exception('ping++支付回调 修改ping支付记录表失败 ping单号为 '.$pingOrderId);
            }

            //插入还款记录表
            $hkData = [
                'UserID'      => $pingOrderInfo['UserID'],     //用户DI
                'ApplyID'     => $pingOrderInfo['ID'],         //订单ID
                'OrderSn'     => $pingOrderInfo['OrderSn'],    //订单编号
                'TotalMoney'  => $amount,                      //支付金额
                'HkTime'      => date('Y-m-d H:i:s',$created), //支付时间
                'TradeNo'     => $tradeNo,                     //支付流水号(ping++交易号)
                'pay'         => $channel,                     //支付方式
                'Type'        => 4,                            //支付状态
            ];
            $hkResult = Db::table('xb_loans_hklist')->insert($hkData);
            if(!$hkResult){
                throw new \Exception('ping++支付回调 插入支付记录表失败 ping单号为 '.$pingOrderId);
            }

            //插入支付记录表
            $payResult = (new Ping())->addPay($pingOrderInfo['ID'],$pingOrderInfo['UserID'],$pingOrderInfo['OrderSn'],$tradeNo,4,$amount,$channel,$created);
            if(!$payResult){
                throw new \Exception('ping++支付回调 插入支付记录表失败 ping单号为 '.$pingOrderId);
            }

            // 提交事务
            Db::commit();
        } catch (\Exception $e) {

            // 回滚事务
            Db::rollback();

            //写入错误日志
            \Think\Log::record($e->getMessage());
            return false;
        }

        //获取还款短信与用户名称 发送成功还款短信通知
        $userInfo = (new Member())->getUserInfo($pingOrderInfo['UserID'],['TrueName','Mobile']);
        $smsTemp = (new SmsTemplate())->getSmsInfo('repayment_Inform');
        $smsTempStr = str_replace(['#name#','#money#'],[$userInfo['TrueName'],$amount],$smsTemp['Content']);
        $result1 = (new CLApi())->sendSMS($userInfo['Mobile'],$smsTempStr);
        $result2 = json_decode($result1,true);

        //写入对接产品记录表
        (new Docking())->addDocking(1,($result2['code'] == 0)?2:3,'chuanglan','ping++回调成功 发送还款成功短信',$result1);

        if($result2['code'] != 0){
            //写入错误日志
            \Think\Log::record('用户成功还款 短信发送失败');
        }

        return true;
    }

    /**
     * 订单展期1 - 展期支付操作
     * @param string $orderId 订单编号
     * @param string $payType 支付类型
     * @return object
     */
    public function orderStage()
    {
        //验证post数据
        $postData = Request()->only('orderId,payType');
        $result = $this->validate($postData,'Order.orderStage');
        if($result !== true){
            returnErrorResult($result);
        }

        //获取订单信息
        $orderInfo = $this->getOrderInfo($postData['orderId']);
        if(!$orderInfo || $orderInfo['LoanStatus'] == 3){
            returnErrorResult('未找到订单信息或还款已结清,请稍后再试');
        }

        //检车产品是否允许展期
        $isOrderOverdue = (new Goods())->isOrderRenewal($orderInfo);
        if(!$isOrderOverdue){
            returnErrorResult('该产品已不允许展期');
        }

        //ping++支付
        (new Ping())->pay('用户展期',$orderInfo['OrderSn'],$orderInfo['zhanqifei'],($postData['payType'] == 1)?'alipay':'wx','用户展期');
    }

    /**
     * 订单展期2 - 展期支付成功后操作
     * @param string $pingOrderId ping支付记录单号
     * @param integer $amount 还款金额/元
     * @param int $created 还款时间
     * @param string $tradeNo 交易流水号
     * @param string $channel 支付方式
     */
    public function orderStageTwo($pingOrderId,$amount,$created,$tradeNo,$channel)
    {
        //获取ping支付记录与订单信息
        $pingOrderInfo = $this->getPingOrderInfo($pingOrderId);
        if(!$pingOrderInfo){
            \Think\Log::record('ping++支付回调 根据ping支付单号寻找贷款订单信息失败-展期 ping单号为 '.$pingOrderId);
            return false;
        }

        // 启动事务
        Db::startTrans();
        try {

            //修改贷款订单状态
            $loanOrder = [
                'YyFkTime' => date('Y-m-d H:i:s',strtotime($pingOrderInfo['YyFkTime']) + (86400 * 6)),
                'xjnums'   => $pingOrderInfo['xjnums'] + 1,
            ];
            $loanResult = Db::table('xb_loans_applylist')->where(['ID' => $pingOrderInfo['ID']])->update($loanOrder);
            if(!$loanResult){
                throw new \Exception('ping++支付回调 修改贷款订单状态失败 ping单号为 '.$pingOrderId);
            }

            //插入续期记录表
            $renewalData = [
                'UserID'     => $pingOrderInfo['UserID'],
                'AppID'      => $pingOrderInfo['ID'],
                'OrderSn'    => $pingOrderInfo['OrderSn'],
                'TradeNo'    => $tradeNo,
                'TotalMoney' => $amount,
                'CreateTime' => date('Y-m-d H:i:s',$created), //支付时间
                'pay'    =>  $channel,
                'PayTime'    => date('Y-m-d H:i:s',$created), //支付时间
                'YyFkTime'   => $loanOrder['YyFkTime'],
                'Type'       => 5,                            //还款类型 线上展期
            ];
            $renewalResult = Db::table('xb_loans_xjapplylist')->insert($renewalData);
            if(!$renewalResult){
                throw new \Exception('ping++支付回调 插入展期记录表失败 ping单号为 '.$pingOrderId);
            }

            //插入支付记录表
            $payResult = (new Ping())->addPay($pingOrderInfo['ID'],$pingOrderInfo['UserID'],$pingOrderInfo['OrderSn'],$tradeNo,5,$amount,$channel,$created);
            if(!$payResult){
                throw new \Exception('ping++支付回调 插入支付记录表失败 ping单号为 '.$pingOrderId);
            }

            // 提交事务
            Db::commit();
        } catch (\Exception $e) {

            // 回滚事务
            Db::rollback();

            //写入错误日志
            \Think\Log::record($e->getMessage());
            return false;
        }

        //获取展期短信与用户名称 发送成功展期短信通知
        $userInfo = (new Member())->getUserInfo($pingOrderInfo['UserID'],['TrueName','Mobile']);
        $smsTemp = (new SmsTemplate())->getSmsInfo('zhanqi');
        $smsTempStr = str_replace(['#name#','#time#'],[$userInfo['TrueName'],date('Y-m-d',time())],$smsTemp['Content']);
        $result1 = (new CLApi())->sendSMS($userInfo['Mobile'],$smsTempStr);
        $result2 = json_decode($result1,true);

        //写入对接产品记录表
        (new Docking())->addDocking(1,($result2['code'] == 0)?2:3,'chuanglan','ping++回调成功 发送成功展期短信',$result1);

        if($result2['code'] != 0){
            //写入错误日志
            \Think\Log::record('用户展期支付成功 短信发送失败');
        }

        return true;
    }

    /**
     * 根据订单ID获取订单信息
     * @param int $orderId 订单ID
     * @return array
     */
    public function getOrderInfo($orderId)
    {
        return db('loans_applylist')->where(['ID|OrderSn' => $orderId])->find();
    }

    /**
     * 根据ping支付单号获取订单信息
     * @param string $pingOrderSn
     * @return array
     */
    public function getPingOrderInfo($pingOrderSn)
    {
        return db('pay_ping')->alias('p')
            ->where(['p.PingOrderSn' => $pingOrderSn,'p.Status' => 2])
            ->join('loans_applylist a','p.OrderSn = a.OrderSn')
            ->field(['*','p.ID as PID','p.Status' => 'PStatus'])
            ->find();
    }

    /**
     * 获取订单应还款金额
     * @param int $orderInfo 订单信息
     */
    public function getOrderShould($orderInfo)
    {
        //检测订单是否逾期并获取逾期天数
        $isOrderOverdue = $this->isOrderOverdue($orderInfo);
        if($isOrderOverdue){
            //最终还款金额 = 到期应还金额 + 逾期金额
            $orderInfo['daoqiMoney'] = $orderInfo['daoqiMoney'] + $this->getOrderPenalty($orderInfo);
        }

        //获取用户部分还款金额
        $partMoney = $this->getOrderPartMoney($orderInfo);

        //获取用户豁免金额
        $reductionMoney = $this->getOrderReductionMoney($orderInfo);

        //最终还款金额
        return (int)$orderInfo['daoqiMoney'] - ($partMoney + $reductionMoney);
    }

    /**
     * 检测订单是否逾期
     * @param array $orderInfo 订单信息
     * @param bool $isLimit 是否加入系统最大可逾期天数判断
     * @return int 逾期天数
     */
    public function isOrderOverdue($orderInfo,$isLimit = true)
    {
        $overtimes = date('Y-m-d', strtotime($orderInfo['YyFkTime'])) . ' 23:59:59';

        //检测是否逾期并返回逾期天数
        if (strtotime($overtimes) < strtotime(date('Y-m-d'))) {

            //获取逾期天数并根据是否根据系统最大可逾期天数 获取订单实际逾期天数
            $days = diffBetweenTwoDays($overtimes,date('Y-m-d'));
            if($isLimit){
                $systemDays = (new System())->getSystemInfo();
                return ($days>$systemDays['yuqijifeidays'])?$systemDays['yuqijifeidays']:$days;
            }else{
                return $days;
            }
        }
        return 0;
    }

    /**
     * 计算逾期订单逾期罚息
     * @param araay $orderInfo
     * @return integer 订单逾期罚息
     */
    public function getOrderPenalty($orderInfo)
    {
        //检测订单是否逾期并获取逾期天数
        $isOrderOverdue = $this->isOrderOverdue($orderInfo);
        if($isOrderOverdue){
            //订单逾期 返回逾期金额 订单申请金额 * 逾期天数 * 逾期利率(%)[订单逾期利率(%)/100]
            return $orderInfo['daoqiMoney'] * $isOrderOverdue * ($orderInfo['yuqililv']/100);
        }
        return 0;
    }

    /**
     * 获取订单部分还款的金额
     * @param int $orderInfo 订单信息
     * @return int 用户借款订单部分还款金额
     */
    public function getOrderPartMoney($orderId)
    {
        $where['OrderSn'] = $orderId['OrderSn'];
        $where['Type'] = 1;
        return db('loans_hklist')->where($where)->sum('TotalMoney');
    }

    /**
     * 获取订单豁免金额
     * @param array $orderInfo 订单信息
     * @return int 订单豁免金额
     */
    public function getOrderReductionMoney($orderInfo)
    {
        return (int)db('loans_applylist')->alias('a')
            ->join('xb_loans_hklist h','a.ID = h.ApplyID')
            ->where(['a.ID' => $orderInfo['ID'],'h.Type' =>'3'])
            ->sum('TotalMoney');
    }

}